<?php

class Quad_MagicProperties extends Quad_Observable {
	
	protected $_data = array();
	
	public function __call($method, $args) {
		if (preg_match('/^(get|set|unset|isset)([A-Z]\w*)$/', $method, $match)) {
			list (, $type, $prop) = $match;
			$prop = self::_uncamelize($prop);

			switch ($type) {
				case 'get':
					return isset($this->_data[$prop]) ? $this->_data[$prop] : null;

				case 'set':
		      $this->_data[$prop] = $args[0];
		      return $this;
							
				case 'unset':
		      unset($this->_data[$prop]);
		      return $this;
							
				case 'isset':
		      return isset($this->_data[$prop]);			
			}
		}
    $class = get_class($this);
    throw new Quad_Exception("Call to undefined function `$method` in class `$class`");
	}

	protected static function _camelize($str) {
		$camel = ucwords(preg_replace('/_([a-z])/e', 'strtoupper("$1")', $str));		
		return $camel;
	}
	
	protected static function _uncamelize($camelized) {
		$uncamel = strtolower(preg_replace('/[A-Z]/', '_$0', $camelized));
		$uncamel = ltrim($uncamel, '_');
		return $uncamel;
	}
	
	public function __set($prop, $value) {
		$setter = 'set' . self::_camelize($prop);
		$this->$setter($value);  
	}
  
  public function __get($prop) {
    $getter = 'get' . self::_camelize($prop);
		return $this->$getter();
  }
  	
	public function __unset($prop) {
		$setter = 'unset' . self::_camelize($prop);
		return $this->$setter();
	}
	
	public function clear() {
		foreach ($this->_data as $prop => $value) {
			unset($this->$prop);
		}
		return $this;
	}
	
	public function __isset($prop) {
    $getter = 'isset' . self::_camelize($prop);
		return $this->$getter();
	}
	
  /**
   * Get or set properties
   * @param [$values=null]  If an array, set properties, otherwise return an array of properties
   * @return $this|array
   */
  public function properties($values = null) {
  	if (is_array($values)) {
	    foreach ($values as $prop => $value) {
				$this->$prop = $value;
	    }
	    return $this;
  	}
  	$props = array();
		foreach ($this->_data as $prop => $value) {
			$val = $this->$prop;
			$props[$prop] = ($val instanceof Quad_Date ? (string) $val : $val);
		}
		return $props;  	
  }
	
}